package com.iflytek.cosmo.ocr.service.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iflytek.cosmo.ocr.common.config.ArgusProperties;
import com.iflytek.cosmo.ocr.common.config.ThreadProperties;
import com.iflytek.cosmo.ocr.common.constant.CommonConstant;
import com.iflytek.cosmo.ocr.common.constant.FileConstant;
import com.iflytek.cosmo.ocr.common.enums.ResultCodeEnum;
import com.iflytek.cosmo.ocr.common.json.Jackson;
import com.iflytek.cosmo.ocr.common.util.FileUtil;
import com.iflytek.cosmo.ocr.common.util.HtmlWordUtil;
import com.iflytek.cosmo.ocr.common.util.ImageUtil;
import com.iflytek.cosmo.ocr.common.util.JSONUtil;
import com.iflytek.cosmo.ocr.common.util.UUIDUtil;
import com.iflytek.cosmo.ocr.dao.OcrAdvFuncDao;
import com.iflytek.cosmo.ocr.dao.OcrResultDao;
import com.iflytek.cosmo.ocr.model.domain.FileInfo;
import com.iflytek.cosmo.ocr.model.domain.MessageOutput;
import com.iflytek.cosmo.ocr.model.domain.OcrResultOutput;
import com.iflytek.cosmo.ocr.model.domain.State;
import com.iflytek.cosmo.ocr.model.entity.OcrAdvFuncEntity;
import com.iflytek.cosmo.ocr.model.entity.OcrResultEntity;
import com.iflytek.cosmo.ocr.service.ArgusPostService;
import com.iflytek.cosmo.ocr.service.ExportTaskService;
import com.iflytek.cosmo.ocr.service.FileService;
import com.iflytek.cosmo.ocr.service.RecogniseService;
import com.iflytek.cosmo.ocr.support.uap.UapClient;
import com.iflytek.cosmo.ocr.web.vo.ModifyRecResultVO;
import com.iflytek.icourt.common.constants.Constants;
import com.iflytek.icourt.model.pdf.Rect;
import com.iflytek.icourt.model.pdf.Sent;
import com.iflytek.icourt.model.pdf.Textline;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

/**
 * 识别服务
 *
 * @author yunsun
 */
@Service
public class RecogniseServiceImpl implements RecogniseService {

    /**
     * 日志记录器
     */
    private Logger logger = LoggerFactory.getLogger(RecogniseServiceImpl.class);

    /**
     * cosmoUrl
     */
    @Value("${cosmo.base-url}")
    private String cosmoUrl;

    /**
     * ThreadProperties
     */
    @Autowired
    private ThreadProperties threadProperties;

    /**
     * FileService
     */
    @Autowired
    private FileService fileService;

    /**
     * RestTemplate
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * OcrResultDao
     */
    @Autowired
    private OcrResultDao ocrResultDao;

    /**
     * 识别服务线程池
     */
    private ExecutorService ocrRecExec;

    /**
     * pdf转图片线程池
     */
    private ExecutorService pdfToImgExec;

    /**
     * UapClient
     */
    @Autowired
    private UapClient uapClient;

    /**
     * ArgusPostService
     */
    @Autowired
    private ArgusPostService argusPostService;

    /**
     * ArgusProperties
     */
    @Autowired
    private ArgusProperties argusProperties;

    // 识别队列数
    private AtomicInteger taskNums = new AtomicInteger(0);

    // pdf转图片队列数
    private AtomicInteger pdfToImgNums = new AtomicInteger(0);
    
    @Autowired
    private OcrAdvFuncDao ocrAdvFuncDao;

    @Autowired
    private ExportTaskService exportTaskService;

    @Override
    public MessageOutput<String> dealFileList(String userId, String dirId, MultipartFile[] multipartFileList,
                                              String ip) {
        // 校验上传文件的格式和大小
        MessageOutput<String> invalidMessage = checkUploadFileTypAndSize(multipartFileList);
        if (invalidMessage != null) {
            return invalidMessage;
        }

        MessageOutput<String> message = null;
        try {
            logger.debug("------- 上传文件开始 -------");
            List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
            int fileListLen = multipartFileList.length;
            if (fileListLen > 1) {
                // 多线程
                List<FileInfo> fileList = dealFileRelation(userId, dirId, multipartFileList);
                fileInfoList.addAll(fileList);
            } else if (fileListLen == 1) {
                FileInfo fileInfo = saveFileInfo(userId, dirId, multipartFileList[0]);
                fileInfoList.add(fileInfo);
            }
            logger.debug("------- 上传文件结束 -------");

            if (fileInfoList != null && fileInfoList.size() > 0) {
                // 发送文件识别
                dealFileRec(fileInfoList);
            }
            logger.debug("------- 完成发送文件处理 -------");
            //增加埋点
            if (argusProperties.getBuryingEnable()) {
            	String fileType = null;
            	Iterator<FileInfo> it = fileInfoList.iterator();
            	while (it.hasNext()) {
					FileInfo fileInfo = (FileInfo) it.next();
					fileType = fileInfo.getFileType();
					switch (fileType) {
					case "pdf":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadPdfNum(), 1, "userId=" + userId, null);
						break;
					case "png":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadPngNum(), 1, "userId=" + userId, null);
						break;
					case "jpg":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadJpgNum(), 1, "userId=" + userId, null);
						break;
					case "jpeg":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadJpegNum(), 1, "userId=" + userId, null);
						break;
					case "bmp":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadBmpNum(), 1, "userId=" + userId, null);
						break;
					case "tif":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadTifNum(), 1, "userId=" + userId, null);
						break;
					case "tiff":
						argusPostService.postAgent(ip, argusProperties.getOcrUploadTiffNum(), 1, "userId=" + userId, null);
						break;
					default:
						break;
					}
				}
            }
            
            message = new MessageOutput<String>(new State(CommonConstant.SUCCESS_CODE),
                    FileConstant.FILE_IMPORT_SUCCESS);
            message.setBody(JSONUtil.toStrByDefault(fileInfoList.get(0)));
        } catch (Exception e) {
            logger.error("文件导入失败，错误原因：" + e.getMessage());
            message = new MessageOutput<String>(new State(CommonConstant.FAIL_CODE), FileConstant.FILE_IMPORT_FAILURES);
        }
        return message;
    }

    private MessageOutput<String> checkUploadFileTypAndSize(MultipartFile[] multipartFileList) {
        // 校验文件格式
        List<String> invalidFileNames = Arrays.stream(multipartFileList).map(MultipartFile::getOriginalFilename)
                .filter(name -> !FileUtil.isValidUploadFile(name))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(invalidFileNames)) {
            return new MessageOutput<>(new State(CommonConstant.FAIL_CODE, "文件格式不支持"),
                    invalidFileNames.stream().collect(Collectors.joining(",")));
        }

        // 校验文件大小
        for (MultipartFile file : multipartFileList) {
            String fileName = file.getOriginalFilename();
            long fileSize = file.getSize();
            if (FileUtil.isValidUploadPic(fileName) && fileSize > CommonConstant.MAX_UPLOAD_PIC_SIZE) {
                // 上传 图片文件大小超过限制
                invalidFileNames.add(fileName);
            } else if (FileUtil.isSuffixEqualsIngnoreCase(fileName, "pdf") &&
                    fileSize > CommonConstant.MAX_UPLOAD_PDF_SIZE) {
                // 上传的 pdf 文件大小超过限制
                invalidFileNames.add(fileName);
            }
        }
        if (CollectionUtils.isNotEmpty(invalidFileNames)) {
            return new MessageOutput<>(new State(CommonConstant.FAIL_CODE, "文件大小超过限制"),
                    invalidFileNames.stream().collect(Collectors.joining(",")));
        }
        return null;
    }

    @Override
    public OcrResultOutput queryRecResultByFileId(String fileId) {
        OcrResultOutput output = new OcrResultOutput();

        OcrResultEntity queryEntity = new OcrResultEntity();
        queryEntity.setFileId(fileId);

        // 查询识别结果
        OcrResultEntity resultEntity = ocrResultDao.selectOne(queryEntity);

        if (resultEntity != null) {
            if(resultEntity.getStatus() == null) resultEntity.setStatus("0"); //默认给个值0  正在识别中  没有进行识别就开始查询了
            output.setId(resultEntity.getId());
            output.setFileId(resultEntity.getFileId());
            output.setStatus(resultEntity.getStatus());
            output.setResult(resultEntity.getResult());
            output.setResultText(resultEntity.getText());
        } else {
            output.setStatus(CommonConstant.RECG_DOING);
        }

        return output;
    }
    
    
    @Override
    public OcrResultOutput queryAdvanceRecResult(String fileId,Short type) {
    	//1歪斜校正&自动旋转 2图像切边
		if(type!=1 && type!=2 && type!=3 ) {
			logger.error("参数type错误，应传:1歪斜校正&自动旋转 2图像切边 3分栏切分!");
			return null;
		}
        OcrResultOutput output = new OcrResultOutput();

        Example example = new Example(OcrAdvFuncEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("fileId", fileId).andEqualTo("opeType", type);
		List<OcrAdvFuncEntity> filesInDB = ocrAdvFuncDao.selectByExample(example);
		if (CollectionUtils.isNotEmpty(filesInDB)) {
			logger.info("{}图像高级功能能识别结果在表里已存在", fileId);
			OcrAdvFuncEntity entity = filesInDB.get(0);
			String newFileId=entity.getId();
			output = this.queryRecResultByFileId(newFileId);
			output.setFileId(fileId);
			return output;
		}else {
			logger.info("{}图像高级功能能识别结果在表里不存在，调用高级功能接口", fileId);
			MessageOutput<Object> out=this.fileService.correctingPic(fileId, type);
			if(out.getState().getOk() == CommonConstant.SUCCESS_CODE) {
				//调用成功 重新查询
				example = new Example(OcrAdvFuncEntity.class);
				criteria = example.createCriteria();
				criteria.andEqualTo("fileId", fileId).andEqualTo("opeType", type);
				filesInDB = ocrAdvFuncDao.selectByExample(example);
				
				OcrAdvFuncEntity entity = filesInDB.get(0);
				String newFileId=entity.getId();
				output = this.queryRecResultByFileId(newFileId);
				output.setFileId(fileId);
				return output;
				
			}else {
				logger.info("{}调用高级功能接口失败，失败原因{}", fileId,out.getBody());
			}
		}

        return output;
    }

    @Override
    public OcrResultOutput doRecByFileId(String fileId) {
        // 查找文件信息
        FileInfo fileInfo = fileService.selectFileInfo(fileId);
        String fileName = fileInfo.getFileName();
        String fileType = fileInfo.getFileType();
        fileType = fileType.toLowerCase();
        // 下载文件数据
        byte[] bytes = null;
        String filePath = fileInfo.getFilePath();
        if (StringUtils.isNotBlank(filePath)) {
            bytes = fileService.getFileBytes(filePath);
        }

        // 进行识别服务
        OcrResultOutput ocrResultOutput = processRecognise(fileName, fileType, bytes);
        bytes = null;
        
        //重新识别之后更新表格
        String ocrResultStr=ocrResultOutput.getResult();
        if(StringUtils.isNotEmpty(ocrResultStr)) {
			  JSONObject bodyJson = JSON.parseObject(ocrResultStr);
		        if(null!=bodyJson) {
		        	JSONArray tableArray = bodyJson.getJSONArray("Table"); 
		            if( null!=tableArray&& !tableArray.isEmpty() && tableArray.size() >0) {
		            	// 请求接口导出 刷新html
		                String html = requestExportHtml(ocrResultStr);
		                if (StringUtils.isNotEmpty(html)) {
		                    ocrResultOutput.setHtml(html);
		                }
		            }
		        }
		 }

        // 保存或更新数据
        logger.debug("------- 更新识别结果 -------");
        OcrResultEntity ocrResultEntity = new OcrResultEntity();
        ocrResultEntity.setFileId(fileId);
        ocrResultEntity.setGroupId(fileInfo.getParentId());
        ocrResultEntity.setStatus(ocrResultOutput.getStatus());
        ocrResultEntity.setResult(ocrResultOutput.getResult());
        ocrResultEntity.setText(ocrResultOutput.getText());
        ocrResultEntity.setHtml(ocrResultOutput.getHtml());
        ocrResultEntity.setIsDelete(0);

        String resultId = addOrUpdateOcrResult(ocrResultEntity);
        ocrResultOutput.setFileId(fileId);
        ocrResultOutput.setId(resultId);
        return ocrResultOutput;
    }

    @Override
    public String addOrUpdateOcrResult(OcrResultEntity ocrResultEntity) {
        if (ocrResultEntity != null) {
            // 查询条件
            Example example = new Example(OcrResultEntity.class);
            Criteria criteria = example.createCriteria();
            // id条件
            String id = ocrResultEntity.getId();
            if (StringUtils.isNotBlank(id)) {
                criteria.andEqualTo("id", id);
            }
            // fileId条件
            String fileId = ocrResultEntity.getFileId();
            if (StringUtils.isNotBlank(fileId)) {
                criteria.andEqualTo("fileId", fileId);
            }
            List<OcrResultEntity> ocrResultList = ocrResultDao.selectByExample(example);

            Date current = new Date();
            if (ocrResultList != null && ocrResultList.size() > 0) {
                // 更新
                ocrResultEntity.setUpdateTime(current);
                ocrResultDao.updateByExampleSelective(ocrResultEntity, example);

                // 删除关联的导出任务记录
                exportTaskService.cleanupByFileId(fileId);

                return ocrResultList.get(0).getId();
            } else {
                // 新增
                String resultId = UUIDUtil.getUUID();
                ocrResultEntity.setId(resultId);
                if (StringUtils.isEmpty(ocrResultEntity.getGroupId())) {
                    ocrResultEntity.setGroupId(ocrResultEntity.getFileId());
                }
                ocrResultEntity.setCreateTime(current);
                ocrResultEntity.setUpdateTime(current);

                ocrResultDao.insert(ocrResultEntity);

                return resultId;
            }
        }
        return  null;
    }

    /**
     * 处理文件信息进行识别
     *
     * @param userId            用户id
     * @param dirId             目录id
     * @param multipartFileList 文件列表
     * @return 文件信息列表
     */
    private List<FileInfo> dealFileRelation(String userId, String dirId, MultipartFile[] multipartFileList) {
        final List<FileInfo> fileInfoList = new ArrayList<FileInfo>();

        logger.debug("------- 多线程处理文件上传 -------");
        try {
            // 多线程，线程数为文件数
            int fileListLen = multipartFileList.length;
            final CountDownLatch latch = new CountDownLatch(fileListLen);
            int poolSize = fileListLen < threadProperties.getMaxUploadThread() ? fileListLen : threadProperties
                    .getMaxUploadThread();
            ExecutorService exec = Executors.newFixedThreadPool(poolSize);
            logger.debug("------- 上传文件处理线程池大小 ------- " + poolSize);
            for (int i = 0; i < fileListLen; i++) {
                final MultipartFile multipartFile = multipartFileList[i];
                Runnable run = new Runnable() {
                    @Override
                    public void run() {
                        // 上传并保存文件信息
                        FileInfo fileInfo = saveFileInfo(userId, dirId, multipartFile);
                        fileInfoList.add(fileInfo);

                        // 如果当前计数为零，则此方法立即返回。
                        latch.countDown();
                    }
                };
                exec.submit(run);
            }
            // 等待latch变为0
            latch.await();
            exec.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return fileInfoList;
    }

    /**
     * 上传并保存文件信息
     *
     * @param userId        用户id
     * @param dirId         目录id
     * @param multipartFile 文件
     * @return 文件信息
     */
    private FileInfo saveFileInfo(String userId, String dirId, MultipartFile multipartFile) {
        try {
            // 文件信息上传到fdfs
            String filePath = fileService.uploadFile(multipartFile);
            long fileSize = multipartFile.getSize();
            String fileName = multipartFile.getOriginalFilename();
            String originalFileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
            String fileType = originalFileType.toLowerCase();

            // 保存文件信息
            FileInfo fileInfo = new FileInfo();
            fileInfo.setDirId(dirId);
            fileInfo.setFileName(fileName.substring(0, fileName.lastIndexOf(".")));
            fileInfo.setFileType(originalFileType);
            fileInfo.setFileSize(fileSize);
            fileInfo.setFilePath(filePath);

            if ("pdf".equalsIgnoreCase(fileType)) {
                // pdf文件，设置页数
                logger.debug("------- 获取pdf总页数-------");
                int pageCount = ImageUtil.getPdfPageCount(multipartFile.getInputStream());
                fileInfo.setFilePage(pageCount);
            } else {
                // 普通文件，设置页数默认1
                fileInfo.setFilePage(1);
            }

            if ("jpg".equalsIgnoreCase(fileType) || "jpeg".equalsIgnoreCase(fileType) || "png".equalsIgnoreCase(fileType) || "bmp".equalsIgnoreCase(fileType)) {
                if (fileSize > CommonConstant.FORMAT_MIN_SIZE) {
                    // 压缩图片文件
                    logger.debug("------- 开始图片压缩-------");

                    double rate = (double) CommonConstant.FORMAT_MIN_SIZE / (double) fileSize;
                    ByteArrayOutputStream reduceStream = (ByteArrayOutputStream) ImageUtil.reduceImgByRate(
                            multipartFile.getInputStream(), rate);
                    if (reduceStream != null) {
                        byte[] bytes = reduceStream.toByteArray();
                        long formatSize = bytes.length;
                        String formatPath = fileService.uploadFile(fileName, "jpg", bytes);
                        bytes = null;
                        reduceStream.close();

                        // 更新格式化信息
                        fileInfo.setFormatType("jpg");
                        fileInfo.setFormatSize(formatSize);
                        fileInfo.setFormatPath(formatPath);
                    }
                }
            }

            if ("tif".equals(fileType) || "tiff".equals(fileType)) {
                // 格式转换
                logger.debug("------- 开始图片格式转换-------");
                ByteArrayOutputStream jpgStream = (ByteArrayOutputStream) ImageUtil.tiff2Jpg(multipartFile
                        .getInputStream());
                if (jpgStream != null) {
                    byte[] bytes = jpgStream.toByteArray();
                    long formatSize = bytes.length;
                    String formatPath = fileService.uploadFile(fileName, "jpg", bytes);
                    bytes = null;
                    jpgStream.close();

                    // 更新格式化信息
                    fileInfo.setFormatType("jpg");
                    fileInfo.setFormatSize(formatSize);
                    fileInfo.setFormatPath(formatPath);
                }
            }

            fileInfo.setUserId(userId);
            String fileId = fileService.saveFileInfo(fileInfo);
            // 更新文件对象中的id
            fileInfo.setId(fileId);
            return fileInfo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理文件信息进行识别
     *
     * @param fileInfoList 文件信息列表
     */
    private void dealFileRec(List<FileInfo> fileInfoList) {

        // 多线程处理识别
        initRecExec();

        int fileListLen = fileInfoList.size();
        for (int i = 0; i < fileListLen; i++) {
            FileInfo fileInfo = fileInfoList.get(i);

            if ("pdf".equalsIgnoreCase(fileInfo.getFileType().toLowerCase())) {
                String filePath = fileInfo.getFilePath();
                byte[] bytes = fileService.getFileBytes(filePath);
                //多线程处理pdf转图片
                initpdfToImgExec();
                Runnable pdfTask = new Runnable() {
                    @Override
                    public void run() {
                        dealPdfFile(fileInfo, bytes);
                    }
                };
                pdfToImgExec.submit(pdfTask);
                logger.info("pdf转图片队列增加1，现在数量为：" + pdfToImgNums.incrementAndGet());
                return;
            }

            Runnable run = new Runnable() {
                @Override
                public void run() {
                    // 获取文件信息
                    String fileId = fileInfo.getId();
                    String fileName = fileInfo.getFileName();
                    String fileType = fileInfo.getFileType();
                    fileType = fileType.toLowerCase();
                    String filePath = fileInfo.getFilePath();
                    // 获取文件数据
                    byte[] bytes = fileService.getFileBytes(filePath);

                    // if ("pdf".equals(fileType)) {
                    // // 处理pdf的流程
                    // dealPdfFile(fileInfo, bytes);
                    // return;
                    // }

                    // 进行识别服务
                    OcrResultOutput ocrResultOutput = processRecognise(fileName, fileType, bytes);

                    // 转换存储对象
                    logger.debug("------- 保存识别结果 -------");
                    OcrResultEntity ocrResultEntity = new OcrResultEntity();
                    ocrResultEntity.setFileId(fileId);
                    ocrResultEntity.setGroupId(fileInfo.getParentId());
                    ocrResultEntity.setStatus(ocrResultOutput.getStatus());
                    ocrResultEntity.setResult(ocrResultOutput.getResult());
                    ocrResultEntity.setText(ocrResultOutput.getText());
                    ocrResultEntity.setHtml(ocrResultOutput.getHtml());
                    addOrUpdateOcrResult(ocrResultEntity);
                    bytes = null;
                }
            };
            ocrRecExec.submit(run);
            logger.info("识别任务加1，当前task任务数量：" + taskNums.incrementAndGet());
        }
    }

    /**
     * 处理pdf文件
     *
     * @param scrFileInfo 源文件信息
     * @param scrBytes    源文件数据
     */
    private void dealPdfFile(FileInfo scrFileInfo, byte[] scrBytes) {
        try {
            logger.debug("------- 开始pdf转换成图片页-------");
            long startTime = System.currentTimeMillis();
            InputStream inputStream = new ByteArrayInputStream(scrBytes);
            List<OutputStream> imgList = ImageUtil.pdfToPng(inputStream);
            long endTime = System.currentTimeMillis();
            logger.info("pdf转图片耗费时间：" + (endTime - startTime));
            logger.info("pdf转图片队列减少1，现在数量为：" + pdfToImgNums.decrementAndGet());
            // 多线程处理识别
            initRecExec();
            int imgListLen = imgList.size();
            for (int i = 0; i < imgListLen; i++) {
                // 页数位置
                int index = i + 1;
                ByteArrayOutputStream outputStream = (ByteArrayOutputStream) imgList.get(i);
                Runnable run = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            //判断父pdf是否存在 如果父文件被删除则不往里面插入
                            FileInfo fileInfoParent = fileService.selectFileInfo(scrFileInfo.getId());
                            if(fileInfoParent.getId() == null)
                            {
                                logger.debug("-------父文件删除不往里面插入-------" + scrFileInfo.getId());
                                return;
                            }

                            // 子文件信息上传到fdfs
                            String fileName = scrFileInfo.getFileName() + "_" + index;
                            String fileType = "png";
                            byte[] bytes = outputStream.toByteArray();
                            long fileSize = bytes.length;
                            String filePath = fileService.uploadFile(fileName, fileType, bytes);
                            outputStream.close();

                            // 保存子文件信息
                            FileInfo fileInfo = new FileInfo();
                            fileInfo.setDirId(scrFileInfo.getDirId());
                            fileInfo.setUserId(scrFileInfo.getUserId());
                            fileInfo.setFileName(fileName);
                            fileInfo.setFileType(fileType);
                            fileInfo.setFileSize(fileSize);
                            fileInfo.setFilePath(filePath);
                            // 子文件添加的属性
                            fileInfo.setParentId(scrFileInfo.getId());
                            fileInfo.setFilePage(index);

                            // 转换后的图片处理
                            if (fileSize > CommonConstant.FORMAT_MIN_SIZE) {
                                // 压缩图片文件
                                logger.debug("------- 开始pdf子图片压缩-------");

                                double rate = (double) CommonConstant.FORMAT_MIN_SIZE / (double) fileSize;
                                InputStream is = new ByteArrayInputStream(bytes);
                                ByteArrayOutputStream reduceStream = (ByteArrayOutputStream) ImageUtil.reduceImgByRate(
                                        is, rate);
                                if (reduceStream != null) {
                                    byte[] reduceBytes = reduceStream.toByteArray();
                                    long formatSize = reduceBytes.length;
                                    String formatPath = fileService.uploadFile(fileName, "jpg", reduceBytes);
                                    reduceStream.close();

                                    // 更新格式化信息
                                    fileInfo.setFormatType("jpg");
                                    fileInfo.setFormatSize(formatSize);
                                    fileInfo.setFormatPath(formatPath);
                                }
                            }
                            String fileId = fileService.saveFileInfo(fileInfo);

                            // 进行识别服务
                            OcrResultOutput ocrResultOutput = processRecognise(fileName, fileType, bytes);

                            // 转换存储对象
                            logger.debug("------- 保存子文件识别结果 -------");
                            OcrResultEntity ocrResultEntity = new OcrResultEntity();
                            ocrResultEntity.setFileId(fileId);
                            ocrResultEntity.setGroupId(fileInfo.getParentId());
                            ocrResultEntity.setStatus(ocrResultOutput.getStatus());
                            ocrResultEntity.setResult(ocrResultOutput.getResult());
                            ocrResultEntity.setText(ocrResultOutput.getText());
                            ocrResultEntity.setHtml(ocrResultOutput.getHtml());
                            addOrUpdateOcrResult(ocrResultEntity);
                            bytes = null;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                };
                ocrRecExec.submit(run);
                logger.info("识别任务加1，当前task任务数量" + taskNums.incrementAndGet());
            }
            logger.debug("------- 结束pdf每页处理 -------");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 进行识别服务
     *
     * @param fileName 文件名
     * @param fileType 文件类型
     * @param bytes    文件数据
     * @return 识别结果
     * @throws Exception Exception
     */
    private OcrResultOutput processRecognise(String fileName, String fileType, byte[] bytes) {
        long startTime = System.currentTimeMillis();
        // ocr结果对象
        OcrResultOutput ocrResultOutput = new OcrResultOutput();

        // 判断后缀名
        if ("jpg".equals(fileType) || "jpeg".equals(fileType) || "png".equals(fileType) || "bmp".equals(fileType)
                || "tif".equals(fileType) || "tiff".equals((fileType))) {
            // 调用ocr引擎
            try {
                long startTime1 = System.currentTimeMillis();
                String result = formOcrService(fileName, bytes);
                long endTime1 = System.currentTimeMillis();
                logger.info("图文识别方法所需要时间：" + (endTime1 - startTime1));
                ocrResultOutput.setStatus(CommonConstant.RECG_SUCCESS);
                ocrResultOutput.setResult(extractResultBody(result));
                ocrResultOutput.setText(extractResultText(result));
            } catch (Exception e) {
                logger.error("进行识别服务-调用ocr引擎出错");
                ocrResultOutput.setStatus(CommonConstant.RECG_FAIL_ENGINE);
            }
        } else if ("doc".equals(fileType) || "docx".equals(fileType)) {
            // word转换成html
            try {
                String html = HtmlWordUtil.wordToHtml(bytes, fileType);
                ocrResultOutput.setStatus(CommonConstant.RECG_SUCCESS);
                ocrResultOutput.setHtml(html);
            } catch (Exception e) {
                logger.error("进行识别服务-word解析出错");
                ocrResultOutput.setStatus(CommonConstant.RECG_FAIL_FORMAT);
            }
        } else if ("txt".equals(fileType)) {
            // text读取文字
            try {
                String text = FileUtil.byteToStr(bytes);
                ocrResultOutput.setStatus(CommonConstant.RECG_SUCCESS);
                ocrResultOutput.setText(text);
            } catch (Exception e) {
                logger.error("进行识别服务-text解析出错");
                ocrResultOutput.setStatus(CommonConstant.RECG_FAIL_FORMAT);
            }
        }
        bytes = null;
        logger.info("识别结束，任务减1，当前task任务数量：" + taskNums.decrementAndGet());
        long endTime = System.currentTimeMillis();
        logger.info("图文识别前后共需要时间：" + (endTime - startTime));
        return ocrResultOutput;
    }

    /**
     * 提取识别结果的原始
     */
    private String extractResultBody(String restResult) {
        String result = StringUtils.EMPTY;
        // 判断rest返回结果是否有值
        if (StringUtils.isNotBlank(restResult)) {
            JsonNode restResultNode = Jackson.parseJsonNode(restResult);

            int msgStatus = restResultNode.get("msgStatus").intValue();
            if (msgStatus == 0) {
                result = restResultNode.get("msgBody").textValue();
            }
        }
        return result;
    }

    /**
     * 提取识别结果的纯文本内容
     */
    private String extractResultText(String restResult) {
        String msgText = StringUtils.EMPTY;
        if (StringUtils.isBlank(restResult)) {
            return msgText;
        }

        try {
            msgText = JSONUtil.getProp(JSONUtil.toJsonNode(restResult), "msgText", String.class);
        } catch (IOException e) {
            logger.warn("解析 ocr 识别结果异常. ocrResult: {}", restResult, e);
        }

        return msgText;
    }

    /**
     * 调用ocr服务生成结果
     *
     * @param fileName 文件名
     * @param bytes    文件内容
     * @return 识别结果
     */
    private String formOcrService(String fileName, byte[] bytes) throws Exception {
        // 请求路径
        String requestUrl = cosmoUrl + "/iflytek/ocr/view/fileExtra";

        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.set("Accept", "text/plain");
        requestHeaders.set("Content-Type", "multipart/form-data");

        ByteArrayResource resource = new ByteArrayResource(bytes) {
            @Override
            public String getFilename() {
                return fileName;
            }
        };

        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        param.add("picFile", resource);
        param.add("name", fileName);

        // 发起请求
        logger.debug("开始调用ocr服务, url: {}", requestUrl);

        String restResult = StringUtils.EMPTY;
        try {
            long startTime1 = System.currentTimeMillis();
            restResult = restTemplate.postForObject(requestUrl, param, String.class);
            long endTime1 = System.currentTimeMillis();
            logger.info("方法所需要时间：" + (endTime1 - startTime1));
            resource = null;
        } catch (Exception e) {
            logger.error("调用ocr服务时出错，错误信息：" + e);
            throw e;
        }

        bytes = null;
        return restResult;
    }

    /**
     * 初始化服务
     */
    private void initRecExec() {
        if (ocrRecExec == null) {
            ocrRecExec = Executors.newFixedThreadPool(threadProperties.getMaxRecogniseThread());
        }
    }

    /**
     * 初始化pdf转图片线程池服务
     */
    private void initpdfToImgExec() {
        if (pdfToImgExec == null) {
            pdfToImgExec = Executors.newFixedThreadPool(threadProperties.getMaxRecogniseThread());
        }
    }

    @Override
    public MessageOutput<String> recogniseCapture(String userId, String dirId, String imageBase64, Boolean saveImage,
            String ip, int operation) {
        MessageOutput<String> result = MessageOutput.failed(String.class);

        File tempFile = null;
        try {
            tempFile = ImageUtil.base64ToTempFile(imageBase64);
        } catch (IOException e) {
            logger.warn("截图上传的base64格式图片内容写入本地临时文件异常");
            return null;
        }
        String fileType = StringUtils.substringAfterLast(tempFile.getName(), ".");
        String fileName = ImageUtil.genCaptureFileName();

        // ocr 识别
        OcrResultOutput ocrResultOutput = new OcrResultOutput();
        try {
            String ocrResult = formOcrService(fileName, IOUtils.toByteArray(new FileInputStream(tempFile)));
            if (StringUtils.isNotBlank(ocrResult)) {
                ocrResultOutput.setStatus(CommonConstant.RECG_SUCCESS);
                ocrResultOutput.setResult(extractResultBody(ocrResult));
                String text = extractResultText(ocrResult);
                ocrResultOutput.setText(text);

                result.setBody(text);
                result.setState(new State(ResultCodeEnum.SUCCESS.getCode()));
            }
        } catch (Exception e) {
            logger.warn("截图上传, 调用 ocr 识别服务抛出异常.", e);
            result.setState(new State(ResultCodeEnum.ENGINE_REQUEST_ERROR.getCode(), "ocr识别失败"));
        }
        //增加埋点
        if (argusProperties.getBuryingEnable()) {
            //UapUser uapUser = uapClient.getUserByUserId(userId);
           // String tags = String
            //        .format("account=%s,name=%s,ip=%s,mac=%s", uapUser.getLoginName(), uapUser.getName(), ip, "");

            String metric = operation == 0 ? argusProperties.getOcrCaptureRecognizeNum() : argusProperties
                    .getOcrBoxChoseRecognizeNum();
            argusPostService.postAgent(ip, metric, 1, "userId=" + userId, null);
        }
        // 保存文件信息
        if (saveImage != null && saveImage) {
            // 文件信息上传到fdfs
            String filePath = null;
            try (FileInputStream fileInputStream = new FileInputStream(tempFile)) {
                filePath = fileService.uploadFile(fileName, fileType, IOUtils.toByteArray(fileInputStream));
            } catch (Exception e) {
                logger.warn("截图上传文件保持到 fastDFS 抛出异常, userId: {}, fileName: {}", userId, fileName, e);
                result.setState(new State(ResultCodeEnum.FASTDFS_UPLOAD_ERROR.getCode(), "文件保存到fastDFS失败"));
                // 如果上传 fastDFS 失败则不再保存数据到数据库, 没有意义
                return result;
            }

            // 保存文件信息
            Date current = new Date();
            FileInfo fileInfo = new FileInfo();
            fileInfo.setDirId(dirId);
            fileInfo.setFileName(fileName);
            fileInfo.setFileType(fileType);
            fileInfo.setFileSize(tempFile.length());
            fileInfo.setFilePath(filePath);
            fileInfo.setUserId(userId);
            String fileId = fileService.saveFileInfo(fileInfo);

            // 保存文件识别结果信息
            OcrResultEntity ocrResultEntity = new OcrResultEntity();
            ocrResultEntity.setId(UUIDUtil.getUUID());
            ocrResultEntity.setFileId(fileId);
            ocrResultEntity.setGroupId(fileId);
            ocrResultEntity.setStatus(ocrResultOutput.getStatus());
            ocrResultEntity.setResult(ocrResultOutput.getResult());
            ocrResultEntity.setText(ocrResultOutput.getText());
            ocrResultEntity.setHtml(ocrResultOutput.getHtml());
            ocrResultEntity.setCreateTime(current);
            ocrResultEntity.setUpdateTime(current);
            ocrResultEntity.setIsDelete(0);
            ocrResultDao.insert(ocrResultEntity);
        }

        return result;
    }

    @Override
    public String viewTableHtml(String fileId) {
        Example example = new Example(OcrResultEntity.class);
        example.createCriteria().andEqualTo("fileId", fileId);
        List<OcrResultEntity> ocrResultEntities = ocrResultDao.selectByExample(example);
        if (CollectionUtils.isEmpty(ocrResultEntities)) {
            throw new IllegalArgumentException("文件无识别记录");
        }
        OcrResultEntity ocrResultEntity = ocrResultEntities.get(0);

        String ocrResultStr = ocrResultEntity.getResult();
        if (StringUtils.isBlank(ocrResultStr)) {
            logger.info("文件识别结果为空");
            return null;
        }
        
        logger.debug("------- 判定识别结果的HTML -------");
        JSONObject bodyJson = JSON.parseObject(ocrResultStr);
        if(null!=bodyJson) {
        	JSONArray tableArray = bodyJson.getJSONArray("Table"); 
            if( null==tableArray||tableArray.isEmpty() || tableArray.size() ==0) {
            	logger.info("文件识别结果无表格");
                return null;
            }
        }

        // 获取 html
        String resultHtml = ocrResultEntity.getHtml();
        if (StringUtils.isBlank(resultHtml)) {
            // 调用接口, 获取文件识别结果的 html 格式并更新到数据
            resultHtml = updateOcrResultHtml(ocrResultEntity.getId(), ocrResultStr);
        }

        // 截取出表格部分
        String tableHtml = null;
        try {
            Document document = Jsoup.parse(resultHtml);
            Elements table = document.body().select("table");
            document.body().empty();
            if (table != null) {
                for (Element element : table) {
                    document.body().append(element.toString());
                }
            }
            tableHtml = document.html().replace("\n", "");
        } catch (Exception e) {
            logger.info("提取html中的表格部分异常. html: {}", resultHtml, e);
        }

        return tableHtml;
    }

    private String updateOcrResultHtml(String resultEntityId, String ocrResultStr) {
        // 请求接口导出 html
        String html = requestExportHtml(ocrResultStr);
        if (StringUtils.isBlank(html)) {
            logger.info("ocr识别结果导出 html 结果为空");
            return null;
        }

        // 导出的 html 保存到数据库
        OcrResultEntity resultEntity = new OcrResultEntity();
        resultEntity.setId(resultEntityId);
        resultEntity.setHtml(html);
        ocrResultDao.updateByPrimaryKeySelective(resultEntity);

        return html;
    }

  /**
     * 将 ocr 识别结果导出成 html 格式
     */
    private String requestExportHtml(String ocrResultStr) {
        String requestUrl = cosmoUrl + "iflytek/ocr/view/export";

        Map<String, Object> body = new HashMap<>();
        body.put("type", "html");
        List<String> ocrResultList = new ArrayList<>();//识别json集合
        ocrResultList.add("{\"task_result\":{\"page\":[" + ocrResultStr + "]}}");
        body.put("ocrResult",ocrResultList);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> request = new HttpEntity<String>(JSONUtil.toStrByDefault(body), headers);
        String respStr = null;
        try {
            respStr = restTemplate.postForObject(requestUrl, request, String.class);
            if (StringUtils.isBlank(respStr)) {
                logger.info("ocr 导出接口返回空");
                return null;
            }
        } catch (Exception e) {
            logger.info("请求ocr结果导出接口异常. url: {}", requestUrl, e);
            return null;
        }

        JSONObject respJson = JSON.parseObject(respStr);
        Integer respCode = respJson.getInteger("code");
        if (respCode == null || respCode.intValue() != 200) {
            logger.info("请求ocr 结果导出返回失败结果. url: {}, respStr: {}", requestUrl, respStr);
            return null;
        }

        byte[] dataBytes = respJson.getBytes("data");

        return new String(dataBytes);
    }

	@Override
	public MessageOutput<String> modifyRecResult(ModifyRecResultVO modifyRecResultVO) {
		try {
			String id=modifyRecResultVO.getId();
			int textLineId=modifyRecResultVO.getTextLineId();
			String textLineSentValue=modifyRecResultVO.getTextLineSentValue();
			System.out.println(textLineSentValue);
			OcrResultEntity queryEntity = new OcrResultEntity();
			queryEntity.setId(id);
			// 查询识别结果
			OcrResultEntity resultEntity = ocrResultDao.selectOne(queryEntity);
			if(null == resultEntity) {
				return MessageOutput.failed(String.class, "识别结果"+id+"不存在");
			}
			int mode=modifyRecResultVO.getMode();
			String finalResult=null;
			if(1 == mode) {
				String type=modifyRecResultVO.getType();
				if(StringUtils.isEmpty(type) || (!"text".equals(type)  && !"table".equals(type))) {
					return MessageOutput.failed(String.class, "文本模式下type不能为空，只能为text或者table");
				}
				String ocrResult=resultEntity.getResult();
				JsonNode resultJSON = JSONUtil.toJsonNode(ocrResult);
				if("text".equals(type)) {
					JsonNode textRegionList = resultJSON.get("TextRegion");
					if (!textRegionList.isNull() && textRegionList.isArray() && textRegionList.size()>0) {
						JsonNode textRegion = textRegionList.get(0);
						 if ( !textRegion.isNull()) {
			                 JsonNode textLineList = textRegion.get("textline");
			                 if (!textLineList.isNull() && textLineList.isArray() && textLineList.size() > 0) {
			                	 JsonNode textLine = textLineList.get(textLineId);
			                	 if ( !textLine.isNull()) {
			                		 JsonNode sentList=textLine.get("sent");
			                		 if (!sentList.isNull() && sentList.isArray() && sentList.size() > 0) {
			                			 JsonNode sent=sentList.get(0);
			                			 if (!sent.isNull()){
			                				 ObjectNode objectNode = (ObjectNode) sent;
				                			 objectNode.put("value",textLineSentValue);
				                			 finalResult=JSONUtil.toStr(resultJSON);
				                			 logger.info("修改后的结果为finalResult：{}",finalResult); 
			                			 }
			                			 
			                		 }
			                	 }
			                 }
			             }
				  }
				}else if("table".equals(type)) {
					JsonNode tableList = resultJSON.get("Table");
					if (!tableList.isNull() && tableList.isArray() && tableList.size()>0) {
						Iterator<JsonNode> tableIterator = tableList.elements();
						boolean findFlag=false;
						while (tableIterator.hasNext() && !findFlag) {
						JsonNode table = tableIterator.next();
						if ( !table.isNull()) {
							JsonNode cellList = table.get("cell");
							if (!cellList.isNull() && cellList.isArray() && cellList.size() > 0) {
								Iterator<JsonNode> realElements = cellList.elements();
								while (realElements.hasNext() && !findFlag) {
									JsonNode cell = realElements.next();
									JsonNode textLineList=cell.get("textline");
									if (!textLineList.isNull() && textLineList.isArray() && textLineList.size() > 0) {
										Iterator<JsonNode> textLineIterator = textLineList.elements();
										while (textLineIterator.hasNext()) {
											JsonNode textLine = textLineIterator.next();
											int idValue=textLine.get("id").asInt();
											if(idValue == textLineId) {
												JsonNode sentList=textLine.get("sent");
						                		 if (!sentList.isNull() && sentList.isArray() && sentList.size() > 0) {
						                			 JsonNode sent=sentList.get(0);
						                			 if (!sent.isNull()){
						                				 ObjectNode objectNode = (ObjectNode) sent;
							                			 objectNode.put("value",textLineSentValue);
							                			 finalResult=JSONUtil.toStr(resultJSON);
							                			 logger.info("修改后的结果为finalResult：{}",finalResult);
							                			 findFlag=true;
								                		 break;
						                			 }
						                			 
						                		 }
						                		 
											}
										}
									}
									
								}

							}
						}
						
					}
				 }
				}
				
			  //更新txet
			  /*String text=resultEntity.getText();
			  if(StringUtils.isNotEmpty(text)) {
				  String textArray[]=text.split("\\n");
				  List<String> textList=Arrays.asList(textArray);
				  textList.set(textLineId, textLineSentValue);
				  
				  String textFinal = String.join("\n",textList);
				  logger.info("textFinal:{}",textFinal);
				  queryEntity.setText(textFinal);
			  }*/
			  
			  if(StringUtils.isNotEmpty(finalResult)) {
				  queryEntity.setResult(finalResult);
				  String fullText=extractOcrResult(finalResult,"2");
				  queryEntity.setText(fullText);
			  }
			}else if(2==mode) {
				queryEntity.setHtml(textLineSentValue);
			}else {
				return MessageOutput.failed(String.class, "编辑模式mode传参错误  1文本编辑模式 2表格编辑模式");
			}
		  ocrResultDao.updateByPrimaryKeySelective(queryEntity);
		  //更新表格
		  if(StringUtils.isNotEmpty(finalResult)) {
			  JSONObject bodyJson = JSON.parseObject(finalResult);
		        if(null!=bodyJson) {
		        	JSONArray tableArray = bodyJson.getJSONArray("Table"); 
		            if( null!=tableArray&& !tableArray.isEmpty() && tableArray.size() >0) {
		            	updateOcrResultHtml(id, finalResult);
		            }
		        }
			  
		  }
          // 删除关联的导出任务记录
          exportTaskService.cleanupByFileId(resultEntity.getFileId());
		  
		} catch (Exception e) {
			e.printStackTrace();
			return MessageOutput.failed(String.class, e.getMessage());
		}
		return MessageOutput.success("修改成功");
	}
	
	/**
	 * 提取纯文本内容
	 * <br>
	 * 适用场景:	<br>
	 * 调用方式:	<br>
	 * 业务逻辑说明<br>
	 *
	 * @param ocrResultPage
	 * @param types
	 * @return
	 * @autho dgyu
	 * @time 2019年10月24日 下午8:02:01
	 */
	private String extractOcrResult(String ocrResultPage, String... types) {
        JSONObject page = JSON.parseObject(ocrResultPage);
        StringBuilder result = new StringBuilder();
        for (String type : types) {
            JSONArray jsonArray = new JSONArray();
            if (Constants.STR_TWO.equals(type) || Constants.STR_SIX.equals(type)) {
                //TextRegion
                extractRegionByName(page, jsonArray, Constants.ResultStruct.TEXT_REGION);
                //Table
                extractTableRegion(page, jsonArray);
                //插图Illustration
                extractRegionByName(page, jsonArray, Constants.ResultStruct.ILLUSTRATION);
            }

            if (Constants.STR_TWO.equals(type) || Constants.STR_THREE.equals(type) || Constants.STR_SIX.equals(type)) {
                //签章Seal
                extractRegionByName(page, jsonArray, Constants.ResultStruct.SEAL);
            }
            if (Constants.STR_TWO.equals(type) || Constants.STR_FOUR.equals(type) || Constants.STR_SIX.equals(type)) {
                //手印Fingerprint
                extractRegionByName(page, jsonArray, Constants.ResultStruct.FINGER_PRINT);
            }
            if (Constants.STR_TWO.equals(type) || Constants.STR_FIVE.equals(type) || Constants.STR_SIX.equals(type)) {
                //图片Graphics
                extractRegionByName(page, jsonArray, Constants.ResultStruct.GRAPHICS);
            }
            if (Constants.STR_SIX.equals(type)) {
                //签名,手写体HANDWRITE
                getTextContent(result, jsonArray, Constants.ResultStruct.HANDWRITE);
            } else if (Constants.STR_TWO.equals(type)) {
                //提取纯文本
                getTextContent(result, jsonArray, null);
            } else {
                return jsonArray.toJSONString();
            }
        }
        return result.toString();
    }
	
	/**
     * 根据区域名称抽取该区域
     *
     * @param page       整张图结果
     * @param jsonArray  区域结果
     * @param regionName 区域名称
     */
    protected void extractRegionByName(JSONObject page, JSONArray jsonArray, String regionName) {
        JSONArray graphics = JSONObject.parseArray(page.getString(regionName));
        if (graphics != null && graphics.size() > 0) {
            jsonArray.addAll(graphics);
        }
    }
    
    /**
     * 抽取表区域
     *
     * @param page      整张图结果
     * @param jsonArray 区域结果
     */
    protected void extractTableRegion(JSONObject page, JSONArray jsonArray) {
        JSONArray tables = JSONObject.parseArray(page.getString(Constants.ResultStruct.TABLE));
        if (tables != null && tables.size() > 0) {
            int tsize = tables.size();
            for (int t = 0; t < tsize; t++) {
                JSONObject table = tables.getJSONObject(t);
                extractRegionByName(table, jsonArray, Constants.ResultStruct.CELL);
            }
        }
    }
    
    /**
     * 获取文本内容
     *
     * @param result    保存文本
     * @param jsonArray 区域结果
     */
    protected void getTextContent(StringBuilder result, JSONArray jsonArray, String extactType) {
        int ksize = jsonArray.size();
        List<Textline> textLines = new ArrayList<Textline>();
        for (int k = 0; k < ksize; k++) {
            JSONObject textRegion = jsonArray.getJSONObject(k);
            if (textRegion == null) {
                continue;
            }
            String textLine = textRegion.getString(Constants.ResultStruct.TEXT_LINE);
            if (StringUtils.isNoneBlank(textLine)) {
                textLines.addAll(JSONObject.parseArray(textLine, Textline.class));
            }
        }
        //纵坐标升序排序
        textLines.sort(Comparator.comparing(Textline::getRect, Comparator.comparing(Rect::getY, (y1, y2) -> {
            return y1 - y2;
        })));
        if (textLines != null && textLines.size() > 0) {
            for (Textline textline : textLines) {
                String type = textline.getType();
                boolean exactHandWrite = Constants.ResultStruct.HANDWRITE.equals(extactType);
                boolean handWrite = Constants.ResultStruct.HANDWRITE.equals(type);
                if ((exactHandWrite && handWrite) || !exactHandWrite) {
                    List<Sent> sents = textline.getSent();
                    if (sents != null && sents.size() > 0) {
                        for (Sent sent : sents) {
                            String value = sent.getValue();
                            result.append(value).append("\n");
                        }
                    }
                }
            }
        }

    }
}
